package drawmodel;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Random;

import javax.media.opengl.GL2;
import javax.swing.JOptionPane;


public class DrawModel {
	 
	// create display list
	private int list=-1;;
	
	// vertex array
	private double[][] vertexSet; 
	
	//face array
	private int[][] triFaceSet; 
	
	// create random object
	private Random random;
	
	// set face and vertex array
	boolean arraySet=false;
	
	/**
	 * 
	 * @param name 
	 * 			the file to be loaded 
	 */
	public DrawModel(String name){
		  createVertexArray(name);
		  random=new Random();
	}

	/**
	 * draw the model
	 * @param gl The OpenGL context to use for rendering
	 */
	public void draw(GL2 gl){
		
		// if array is not set return nothing
		 if(!arraySet){
			 return;	 
		 }
		
		 // generate the list
        if(list != -1)
        {
            gl.glCallList(list);
            return;
        }
        // Create a new draw list
        list = gl.glGenLists(1);
       
       
        gl.glNewList(list, GL2.GL_COMPILE);


        gl.glPushMatrix();
       
		 gl.glBegin(GL2.GL_TRIANGLES);
	        for(int i = 0 ; i< triFaceSet.length ; i++)
	        {
	        	//create random colours to each face
	        	double r=random.nextDouble();
	        	double g=random.nextDouble();
	        	double b=random.nextDouble();
	        	
	        	// set the color
	        	gl.glColor3d(r, g, b);
	        	
	        	//calculate normal for each face
	            gl.glNormal3dv(calculateNormal(i),0);
	            // draw a vertex
	        	gl.glVertex3dv(vertexSet[triFaceSet[i][0]], 0);
	        	gl.glVertex3dv(vertexSet[triFaceSet[i][1]], 0);
	        	gl.glVertex3dv(vertexSet[triFaceSet[i][2]], 0);
	        	
	        }
	        gl.glEnd();
	        gl.glPopMatrix();
	   
	      // Finish the draw list
	        gl.glEndList();
	        
       
 }
     
	 
    /**
     * Calculates the face normal by calculating the normalised cross product
     * of two edge vectors
     * @param f The face for which the normal is to be calculated
     * @return The face normal
     */
	 private double [] calculateNormal(int f)
	    {
	    	
	    	 double []a  = vertexSet[triFaceSet[f][0]];
	    	 double []b  = vertexSet[triFaceSet[f][1]];
	    	 double []c  = vertexSet[triFaceSet[f][2]];
	    	
	    	 double [] ab = {b[0] - a[0],
                     b[1] - a[1],
                     b[2] - a[2]};
	    	 double [] ac = {c[0] - a[0],
                     c[1] - a[1],
                     c[2] - a[2]};
                     
	    	 double x = (ab[1] * ac[2]) - (ab[2] * ac[1]);
	    	 double y = (ab[2] * ac[0]) - (ab[0] * ac[2]);
	    	 double z = (ab[0] * ac[1]) - (ab[1] * ac[0]);
      
	    	 double magnitude = (float)Math.sqrt((x*x) + (y*y) + (z*z));
		      x = x / magnitude;
		      y = y / magnitude;
		      z = z / magnitude;
		      double [] retVal = {x,y,z};
		      return retVal;
	 }
	 
	  /**
	   * Parses the tri file and populates your array of vertex data and faces
      *
	   * @param filename
	   *          The name of the file containing the vertex and faces.
	   */
	  private void createVertexArray(String filename) {
	    BufferedReader reader = null;

	    try {
	      // Attempt to open the file.
	      reader = new BufferedReader(new FileReader(filename));

	      // Read and parse each line.
	      String line = null;
	      int varrayNum=0;
	      int farrayNum=0;
	      
	      // loop throught each line in the file
	      while ((line = reader.readLine()) != null) {
	    	String[] arr=line.split(" ");
	    	
	    	// set up vertex and face array
	    	if(arr.length==2){
	    		vertexSet = new double[Integer.parseInt(arr[0])][3];
	    		triFaceSet=new int[Integer.parseInt(arr[1])][3];
	    	}
	    	
	    	// set the values for vertex
	    	if(arr.length==3){
	    		vertexSet[varrayNum][0]= Double.parseDouble(arr[0]);
	    		vertexSet[varrayNum][1]= Double.parseDouble(arr[1]);
	    		vertexSet[varrayNum][2]= Double.parseDouble(arr[2]);
	    		varrayNum++;
	    	}
	    	
	    	// set values for faces
	    	if(arr.length==4){
	 	    	triFaceSet[farrayNum][0]=Integer.parseInt(arr[1]);
	 	    	triFaceSet[farrayNum][1]=Integer.parseInt(arr[2]);
	 	    	triFaceSet[farrayNum][2]=Integer.parseInt(arr[3]);
	   	    	farrayNum++;
	    	}
	    	
	    		      
	      }
	      arraySet=true;
	    }
	     catch (Exception e) {
	      //e.printStackTrace();
	      JOptionPane.showMessageDialog(null,"File not valid \" Load the model again");
	      arraySet=false;
	    }
	    finally {
	      // Always close the reader, if it has been opened.
	      try {
	        if (reader != null) {
	          reader.close();
	        }
	      }
	      catch (IOException e) {
	        e.printStackTrace();
	      }
	    }
	  }
/**
 * Number of faces in the model
 * @return face lenght
 */
 public int numOfFaces(){
	 if(arraySet){
	 return triFaceSet.length;
	 }else{
		 return 0;
	 }
	 
 }
 
 /** 
  *  Number of vertices
  * @return vertex length
  */
 public int numOfVetrices(){
	 if(arraySet){
		return vertexSet.length;
	 }else{
		return 0; 
	 }
}
 
}
